package org.kth.dks.test_bed;

import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;

import org.kth.dks.DKSObject;
import org.kth.dks.dks_comm.ConnectionManager;
import org.kth.dks.dks_comm.DKSRef;
import org.kth.dks.dks_exceptions.DKSRefNoResponse;
import org.kth.dks.dks_node.DKSNode;

public class TestDKS {
  DKSRef myDKSRef = null;
  DKSNode myDKSNode = null;

  public static void main(String[] args) {
    if( args.length != 2 && args.length != 4 ) {
      System.out.println("Usage: ID1 URL1");
      System.out.println("Usage: ID1 URL1 ID2 URL2");
      System.exit(0);
    }

    TestDKS testinterface = new TestDKS();
    testinterface.doTest( args );
  }

  private void showMyIP() {
    String myIP = "UnKnown Host";
    try {
      myIP = InetAddress.getLocalHost().getHostAddress();
    }
    catch (UnknownHostException uhexp) {
      uhexp.printStackTrace();
    }
    System.out.println("My IP: " + myIP);
  }

  private void start( String [] args ) {
    int myid = Integer.parseInt( args[0] );
    URL url1 = null;
    try {
      url1 = new URL(args[1]);
    }
    catch (MalformedURLException ex) {
      System.out.println("Error: URL1 is not valid!");
      System.exit(0);
    }

    int myport = url1.getPort();
    String myip = null;
    try {
      myip = InetAddress.getByName(url1.getHost()).getHostAddress();
    }
    catch (UnknownHostException ex) {
      System.out.println("Error: URL1 is not valid!");
      System.exit(0);
    }

    ConnectionManager cm = null;
    try {
      myDKSRef = DKSRef.newDKSRef("dks://"+myip+":"+myport+"/0/"+myid+"/0");;
      myDKSNode = new DKSNode();
      cm = ConnectionManager.newInstance(myport); // Static factory only used for testing, should use getInstance (singleton)
      myDKSNode.setConnectionManager(cm, myDKSRef);
    } catch (Exception ex) {
      ex.printStackTrace(); return;
    }
  }

  private void join( String [] args ) throws DKSRefNoResponse {
    DKSRef dest = null;

    if( args.length == 4 ) {//Join to an existing node
      URL url2 = null;
      int id2 = Integer.parseInt( args[2] );
      try {
        url2 = new URL( args[3] );
      }
      catch (MalformedURLException ex1) {
        System.out.println("Error: URL2 is not valid!");
        System.exit(0);
      }

      int port2 = url2.getPort();
      String ip2 = null;
      try {
        ip2 = InetAddress.getByName(url2.getHost()).getHostAddress();
        dest = DKSRef.newDKSRef("dks://"+ip2+":"+port2+"/0/"+id2+"/0");
      }  catch (Exception ex) {
        System.out.println("Error: URL2 is not valid!");
        System.exit(0);
      }
    }

    myDKSNode.newNode( myDKSRef, dest );
  }

  private void leave() {
    myDKSNode.prepareForLeave();
  }

  private void setDKSPrintLevel() {
    System.out.print("Enter print level: ");
    System.out.println();
    System.out.println(Integer.parseInt(getInput()));
  }

  private void insert() {
    try {
      String in1 = null, in2 = null;
      long key = 0;
      String value = null;

      System.out.print("Enter Key:");
      in1 = getInput();
      //System.out.println();
      System.out.print("Enter Value:");
      in2 = getInput();
      System.out.println();

      key = Long.parseLong(in1);
      value = in2;

      //((DKS_DHT)myDKSNode).insert( key, new DKSObject(value.getBytes()) );
    }catch( Exception e ) {
      e.printStackTrace();
    }
  }

  private void search() {
    try {
      String in1 = null;
      long key = 0;

      System.out.print("Enter Key:");
      in1 = getInput();
      System.out.println();

      key = Long.parseLong(in1);

      DKSObject [] result;
      result = myDKSNode.lookup( key );
      if (result.length == 0) {
        System.out.println("Search Result:EMPTY");
      } else {
        String t = "";
        for( int i = 0 ; i < result.length ; i++ )
          t = t + new String(result[i].getData()) + " ";
        System.out.println("Search Result:" + t);
      }
    }catch( Exception e ) {
      e.printStackTrace();
    }
  }

  private void remove() {
    try {
      String in1 = null, in2 = null;
      long key = 0;
      String value = null;

      System.out.print("Enter Key:");
      in1 = getInput();
      System.out.println();
      System.out.print("Enter Value:");
      in2 = getInput();
      System.out.println();

      key = Long.parseLong(in1);
      value = in2;

      DKSObject obj = new DKSObject(value.getBytes());
      //((DKS_DHT)myDKSNode).remove(key, obj);
    }catch( Exception e ) {
      e.printStackTrace();
    }
  }

  private void sleep( long msec ) {
    if( msec == 0 )
      return;

    if( msec == -1 ) {
      try {
        System.in.read();
      }
      catch (IOException ex1) {
        ex1.printStackTrace();
      }
      return;
    }

    try {
      Thread.sleep( msec );
    }
    catch (InterruptedException ex) {
      ex.printStackTrace();
    }
  }

  private String getInput() {
    byte [] inputbuff = new byte[512];
    int len = 0;
    String input = null;

    try {
      len = System.in.read(inputbuff);
      input = new String( inputbuff, 0, len-1 );
    }
    catch (IOException ex1) {
      ex1.printStackTrace();
    }
    return input;
  }

  private void doTest( String [] args ) {
    String command = null;
    int choice = 0;

    while( true ) {
      System.out.println("DKS TEST PROGRAM");
      System.out.println("1-Start.");
      System.out.println("2-Join.");
      System.out.println("3-Show IP.");
      System.out.println("4-Print Ring.");
      System.out.println("5-Insert.");
      System.out.println("6-Search.");
      System.out.println("7-Remove.");
      System.out.println("8-Leave.");
      System.out.println("9-Exit.");
      System.out.println("10-Set DKS PrintLevel");
      System.out.print("Enter Command:");
      try {
        command = getInput();
        choice = Integer.parseInt(command);
      }
      catch (Exception e) {
        choice = 0;
      }

      switch (choice) {
        case 0:
          break;
        case 1:
          start(args);
          break;
        case 2:
          try { join(args); } catch (Exception ex) { ex.printStackTrace(); }
          break;
        case 3:
          showMyIP();
          break;
        case 4:
//          printRing();
          break;
        case 5:
          insert();
          break;
        case 6:
          search();
          break;
        case 7:
          remove();
          break;
        case 8:
          leave();
          break;
        case 9:
          System.exit(0);
          break;
        case 10:
	  setDKSPrintLevel();
	  break;
      }//switch
    }//while
  }//showMenu
}//class
